package main

import (
	"fmt"
	"log"
	"math/rand"
	"sync"
	"time"

	"rank/pkg/schema"

	"github.com/go-resty/resty/v2"
	"github.com/pkg/errors"
)

const (
	UserKey = "X-Robot-Index"
)

const (
	None = iota
	Idle
	Login
	Token
)

var (
	stateMachine = map[int][]int{
		None:  {Login},
		Login: {Token},
		Token: {Idle},
	}
)

type robot struct {
	sync.RWMutex

	Nick  string `csv:"nick"`  // 登录时的标识
	Level uint8  `csv:"level"` // 等级
	Value uint16 `csv:"value"` // 初始值

	State int // 控制状态机
	cli   *resty.Client
	rnd   *rand.Rand
}

func makeURL(path string) string {
	return fmt.Sprintf("/svr/v1/%v", path)
}

func (r *robot) reset() error {
	return nil
}

func (r *robot) login() error {
	return nil
}

func (r *robot) updateRank() error {
	req := schema.NoticeReq{
		PID:   r.Nick,
		Level: r.Level,
		Value: r.Value,
	}
	if err := r.postAction(makeURL("rank/notice"), req, nil); err != nil {
		return err
	}

	return nil
}

func (r *robot) Run() (err error) {
	r.rnd = rand.New(rand.NewSource(time.Now().UnixMicro()))
	r.State = None
	r.cli = restyCli

	for {
		switch r.State {
		case None:
			log.Printf("create robot %v\n", r.Nick)
		case Idle:
			err = r.reset()
		case Login:
			err = r.login()
		case Token:
			err = r.updateRank()
		default:
			log.Fatalf("unknown state,%v", r.State)
		}

		if err == nil {
			arr := stateMachine[r.State]
			length := len(arr)
			if length > 0 {
				r.State = arr[r.rnd.Intn(length)]
			}
		}
		time.Sleep(time.Second * time.Duration(r.rnd.Intn(*interval)+1)) // [min,max)
	}
}

func (r *robot) postAction(url string, param, data interface{}) error {
	result := &schema.Response{Data: data}
	rsp, err := r.cli.R().SetHeader(UserKey, r.Nick).SetBody(param).SetResult(result).Post(url)
	if err != nil {
		log.Printf("%v,%v\n", r.Nick, err.Error())
		return err
	}

	if rsp.IsError() {
		return errors.Errorf("bad http code %v", rsp.StatusCode())
	}

	if result.Code != 0 {
		return errors.Errorf("bad result code %v,%v", result.Code, result.Message)
	}

	return nil
}
